package com.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.demo.mapper.CourseMapper;
import com.demo.mapper.ScheduleMapper;
import com.demo.mapper.ScheduleRuleMapper;
import com.demo.mapper.TimeSlotMapper;
import com.demo.pojo.entity.Classroom;
import com.demo.pojo.entity.Course;
import com.demo.pojo.entity.Schedule;
import com.demo.pojo.entity.ScheduleRule;
import com.demo.pojo.entity.TimeSlot;
import com.demo.service.ClassroomService;
import com.demo.service.IntelligentScheduleService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 智能排课算法服务实现类
 */
public class IntelligentScheduleServiceImpl implements IntelligentScheduleService {
    
    @Autowired
    private ScheduleMapper scheduleMapper;
    
    @Autowired
    private CourseMapper courseMapper;
    
    @Autowired
    private ScheduleRuleMapper scheduleRuleMapper;
    
    @Autowired
    private ClassroomService classroomService;
    
    @Autowired
    private TimeSlotMapper timeSlotMapper;
    
    @Override
    public boolean executeIntelligentSchedule(String semester) {
        try {
            System.out.println("开始执行智能排课，学期：" + semester);
            
            // 1. 获取所有需要排课的课程
            List<Course> courses = courseMapper.selectList(null);
            if (courses.isEmpty()) {
                System.out.println("没有找到课程数据");
                return false;
            }
            System.out.println("找到课程数量：" + courses.size());
            
            // 2. 获取排课规则
            List<ScheduleRule> rules = scheduleRuleMapper.selectList(
                new QueryWrapper<ScheduleRule>().eq("is_enabled", 1)
            );
            System.out.println("找到排课规则数量：" + rules.size());
            
            // 3. 检查是否有可用的教室和时间段
            List<Classroom> classrooms = classroomService.getAvailableClassroomsByType("普通教室");
            if (classrooms.isEmpty()) {
                System.out.println("没有找到可用教室");
                return false;
            }
            
            QueryWrapper<TimeSlot> timeSlotQuery = new QueryWrapper<>();
            timeSlotQuery.eq("semester", semester).eq("status", 1);
            List<TimeSlot> timeSlots = timeSlotMapper.selectList(timeSlotQuery);
            if (timeSlots.isEmpty()) {
                System.out.println("没有找到可用时间段，学期：" + semester);
                return false;
            }
            
            System.out.println("找到教室数量：" + classrooms.size() + "，时间段数量：" + timeSlots.size());
            
            // 4. 执行遗传算法排课
            List<Schedule> schedules = geneticAlgorithmSchedule(courses, rules, semester);
            if (schedules.isEmpty()) {
                System.out.println("遗传算法排课失败，没有生成排课结果");
                return false;
            }
            
            System.out.println("生成排课结果数量：" + schedules.size());
            
            // 5. 保存排课结果
            int successCount = 0;
            for (Schedule schedule : schedules) {
                try {
                    scheduleMapper.insert(schedule);
                    successCount++;
                } catch (Exception e) {
                    System.err.println("保存排课失败：" + e.getMessage());
                }
            }
            
            System.out.println("成功保存排课数量：" + successCount);
            return successCount > 0;
            
        } catch (Exception e) {
            System.err.println("智能排课执行失败：" + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }
    
    /**
     * 遗传算法排课
     */
    private List<Schedule> geneticAlgorithmSchedule(List<Course> courses, 
                                                   List<ScheduleRule> rules, 
                                                   String semester) {
        try {
            System.out.println("开始遗传算法排课");
            
            // 简化版本：直接为每个课程生成一个排课
            List<Schedule> schedules = new ArrayList<>();
            
            for (Course course : courses) {
                Schedule schedule = createRandomSchedule(course, semester);
                if (schedule != null) {
                    schedules.add(schedule);
                }
            }
            
            System.out.println("遗传算法排课完成，生成排课数量：" + schedules.size());
            return schedules;
            
        } catch (Exception e) {
            System.err.println("遗传算法排课失败：" + e.getMessage());
            e.printStackTrace();
            return new ArrayList<>();
        }
    }
    
    /**
     * 初始化种群
     */
    private List<List<Schedule>> initializePopulation(List<Course> courses, String semester) {
        List<List<Schedule>> population = new ArrayList<>();
        
        for (int i = 0; i < 50; i++) { // 种群大小50
            List<Schedule> individual = new ArrayList<>();
            for (Course course : courses) {
                Schedule schedule = createRandomSchedule(course, semester);
                individual.add(schedule);
            }
            population.add(individual);
        }
        
        return population;
    }
    
    /**
     * 创建随机排课
     */
    private Schedule createRandomSchedule(Course course, String semester) {
        try {
            Schedule schedule = new Schedule();
            schedule.setCourseId(course.getCourseId());
            schedule.setTeacherId(course.getTeacherId());
            schedule.setScheduleType("正常");
            schedule.setStatus("ACTIVE");
            schedule.setPriority(3);
            schedule.setIsFixed(0);
            schedule.setCreateTime(new Date());
            schedule.setUpdateTime(new Date());
            
            // 随机分配教室
            List<Classroom> classrooms = classroomService.getAvailableClassroomsByType("普通教室");
            if (!classrooms.isEmpty()) {
                Random random = new Random();
                Classroom classroom = classrooms.get(random.nextInt(classrooms.size()));
                schedule.setClassroomId(classroom.getClassroomId());
            } else {
                // 如果没有可用教室，使用默认教室ID
                schedule.setClassroomId(1L);
            }
            
            // 随机分配时间段
            QueryWrapper<TimeSlot> timeSlotQuery = new QueryWrapper<>();
            timeSlotQuery.eq("semester", semester).eq("status", 1);
            List<TimeSlot> timeSlots = timeSlotMapper.selectList(timeSlotQuery);
            if (!timeSlots.isEmpty()) {
                Random random = new Random();
                TimeSlot timeSlot = timeSlots.get(random.nextInt(timeSlots.size()));
                schedule.setTimeSlotId(timeSlot.getTimeSlotId());
            } else {
                // 如果没有可用时间段，使用默认时间段ID
                schedule.setTimeSlotId(1L);
            }
            
            // 随机分配班级（这里简化处理，实际应该根据课程和班级的关联关系）
            schedule.setClazzId(1L);
            
            return schedule;
        } catch (Exception e) {
            e.printStackTrace();
            // 返回一个基本的排课对象
            Schedule schedule = new Schedule();
            schedule.setCourseId(course.getCourseId());
            schedule.setTeacherId(course.getTeacherId());
            schedule.setClassroomId(1L);
            schedule.setTimeSlotId(1L);
            schedule.setClazzId(1L);
            schedule.setScheduleType("正常");
            schedule.setStatus("ACTIVE");
            schedule.setPriority(3);
            schedule.setIsFixed(0);
            schedule.setCreateTime(new Date());
            schedule.setUpdateTime(new Date());
            return schedule;
        }
    }
    
    /**
     * 计算适应度
     */
    private Map<List<Schedule>, Double> calculateFitness(List<List<Schedule>> population, 
                                                         List<ScheduleRule> rules) {
        Map<List<Schedule>, Double> fitness = new HashMap<>();
        
        for (List<Schedule> individual : population) {
            double score = calculateScheduleQuality(individual);
            fitness.put(individual, score);
        }
        
        return fitness;
    }
    
    /**
     * 种群进化
     */
    private List<List<Schedule>> evolvePopulation(List<List<Schedule>> population, 
                                                Map<List<Schedule>, Double> fitness) {
        List<List<Schedule>> newPopulation = new ArrayList<>();
        
        // 选择最优个体
        List<List<Schedule>> sortedPopulation = population.stream()
                .sorted((a, b) -> Double.compare(fitness.get(b), fitness.get(a)))
                .collect(Collectors.toList());
        
        // 保留前20%的个体
        int eliteSize = (int) (population.size() * 0.2);
        newPopulation.addAll(sortedPopulation.subList(0, eliteSize));
        
        // 生成新个体
        while (newPopulation.size() < population.size()) {
            List<Schedule> parent1 = tournamentSelection(population, fitness);
            List<Schedule> parent2 = tournamentSelection(population, fitness);
            
            List<Schedule> offspring = crossover(parent1, parent2);
            offspring = mutate(offspring);
            
            newPopulation.add(offspring);
        }
        
        return newPopulation;
    }
    
    /**
     * 锦标赛选择
     */
    private List<Schedule> tournamentSelection(List<List<Schedule>> population, 
                                              Map<List<Schedule>, Double> fitness) {
        Random random = new Random();
        List<Schedule> best = null;
        double bestFitness = Double.NEGATIVE_INFINITY;
        
        for (int i = 0; i < 5; i++) { // 锦标赛大小5
            List<Schedule> candidate = population.get(random.nextInt(population.size()));
            double candidateFitness = fitness.get(candidate);
            if (candidateFitness > bestFitness) {
                best = candidate;
                bestFitness = candidateFitness;
            }
        }
        
        return best;
    }
    
    /**
     * 交叉操作
     */
    private List<Schedule> crossover(List<Schedule> parent1, List<Schedule> parent2) {
        // 单点交叉
        Random random = new Random();
        int crossoverPoint = random.nextInt(parent1.size());
        
        List<Schedule> offspring = new ArrayList<>();
        offspring.addAll(parent1.subList(0, crossoverPoint));
        offspring.addAll(parent2.subList(crossoverPoint, parent2.size()));
        
        return offspring;
    }
    
    /**
     * 变异操作
     */
    private List<Schedule> mutate(List<Schedule> individual) {
        Random random = new Random();
        if (random.nextDouble() < 0.1) { // 变异概率10%
            int index = random.nextInt(individual.size());
            Schedule schedule = individual.get(index);
            // 随机改变教室或时间段
            // 这里需要根据实际业务逻辑实现
        }
        return individual;
    }
    
    /**
     * 获取最优解
     */
    private List<Schedule> getBestSolution(List<List<Schedule>> population, 
                                         List<ScheduleRule> rules) {
        return population.stream()
                .max((a, b) -> Double.compare(calculateScheduleQuality(a), calculateScheduleQuality(b)))
                .orElse(new ArrayList<>());
    }
    
    @Override
    public boolean checkConstraints(Schedule schedule) {
        // 检查教师时间冲突
        QueryWrapper<Schedule> teacherQuery = new QueryWrapper<>();
        teacherQuery.eq("teacher_id", schedule.getTeacherId())
                   .eq("time_slot_id", schedule.getTimeSlotId())
                   .ne("schedule_id", schedule.getScheduleId());
        long teacherConflict = scheduleMapper.selectCount(teacherQuery);
        
        // 检查教室时间冲突
        QueryWrapper<Schedule> classroomQuery = new QueryWrapper<>();
        classroomQuery.eq("classroom_id", schedule.getClassroomId())
                     .eq("time_slot_id", schedule.getTimeSlotId())
                     .ne("schedule_id", schedule.getScheduleId());
        long classroomConflict = scheduleMapper.selectCount(classroomQuery);
        
        return teacherConflict == 0 && classroomConflict == 0;
    }
    
    @Override
    public List<Schedule> optimizeSchedule(List<Schedule> schedules) {
        // 使用模拟退火算法优化
        return simulatedAnnealing(schedules);
    }
    
    /**
     * 模拟退火算法
     */
    private List<Schedule> simulatedAnnealing(List<Schedule> schedules) {
        double temperature = 1000.0;
        double coolingRate = 0.95;
        List<Schedule> current = new ArrayList<>(schedules);
        List<Schedule> best = new ArrayList<>(schedules);
        
        while (temperature > 1.0) {
            List<Schedule> neighbor = generateNeighbor(current);
            
            double currentEnergy = calculateScheduleQuality(current);
            double neighborEnergy = calculateScheduleQuality(neighbor);
            
            if (neighborEnergy > currentEnergy || 
                Math.random() < Math.exp((neighborEnergy - currentEnergy) / temperature)) {
                current = neighbor;
                if (neighborEnergy > calculateScheduleQuality(best)) {
                    best = new ArrayList<>(neighbor);
                }
            }
            
            temperature *= coolingRate;
        }
        
        return best;
    }
    
    /**
     * 生成邻域解
     */
    private List<Schedule> generateNeighbor(List<Schedule> schedules) {
        List<Schedule> neighbor = new ArrayList<>(schedules);
        Random random = new Random();
        
        // 随机交换两个排课的时间或教室
        if (neighbor.size() >= 2) {
            int index1 = random.nextInt(neighbor.size());
            int index2 = random.nextInt(neighbor.size());
            
            Schedule schedule1 = neighbor.get(index1);
            Schedule schedule2 = neighbor.get(index2);
            
            // 交换教室
            Long tempClassroomId = schedule1.getClassroomId();
            schedule1.setClassroomId(schedule2.getClassroomId());
            schedule2.setClassroomId(tempClassroomId);
        }
        
        return neighbor;
    }
    
    @Override
    public boolean resolveConflicts(List<Schedule> schedules) {
        // 解决冲突的启发式算法
        boolean hasConflict = true;
        int maxIterations = 100;
        int iteration = 0;
        
        while (hasConflict && iteration < maxIterations) {
            hasConflict = false;
            
            for (int i = 0; i < schedules.size(); i++) {
                for (int j = i + 1; j < schedules.size(); j++) {
                    Schedule schedule1 = schedules.get(i);
                    Schedule schedule2 = schedules.get(j);
                    
                    if (hasConflict(schedule1, schedule2)) {
                        hasConflict = true;
                        resolveConflict(schedule1, schedule2);
                    }
                }
            }
            
            iteration++;
        }
        
        return !hasConflict;
    }
    
    /**
     * 检查两个排课是否有冲突
     */
    private boolean hasConflict(Schedule schedule1, Schedule schedule2) {
        // 教师冲突
        if (schedule1.getTeacherId().equals(schedule2.getTeacherId()) &&
            schedule1.getTimeSlotId().equals(schedule2.getTimeSlotId())) {
            return true;
        }
        
        // 教室冲突
        if (schedule1.getClassroomId().equals(schedule2.getClassroomId()) &&
            schedule1.getTimeSlotId().equals(schedule2.getTimeSlotId())) {
            return true;
        }
        
        return false;
    }
    
    /**
     * 解决冲突
     */
    private void resolveConflict(Schedule schedule1, Schedule schedule2) {
        // 优先调整优先级低的排课
        if (schedule1.getPriority() > schedule2.getPriority()) {
            adjustSchedule(schedule1);
        } else {
            adjustSchedule(schedule2);
        }
    }
    
    /**
     * 调整排课
     */
    private void adjustSchedule(Schedule schedule) {
        // 尝试调整到其他时间段或教室
        // 这里需要根据实际业务逻辑实现
    }
    
    @Override
    public double calculateScheduleQuality(List<Schedule> schedules) {
        double score = 0.0;
        
        // 1. 教师时间分布均匀性
        score += calculateTeacherDistributionScore(schedules);
        
        // 2. 教室利用率
        score += calculateClassroomUtilizationScore(schedules);
        
        // 3. 学生课程冲突最小化
        score += calculateStudentConflictScore(schedules);
        
        // 4. 教师偏好满足度
        score += calculateTeacherPreferenceScore(schedules);
        
        return score;
    }
    
    /**
     * 计算教师时间分布分数
     */
    private double calculateTeacherDistributionScore(List<Schedule> schedules) {
        // 计算每个教师的时间分布均匀性
        Map<Long, List<Schedule>> teacherSchedules = schedules.stream()
                .collect(Collectors.groupingBy(Schedule::getTeacherId));
        
        double totalScore = 0.0;
        for (List<Schedule> teacherSchedule : teacherSchedules.values()) {
            // 计算时间分布的方差，方差越小分数越高
            double variance = calculateTimeDistributionVariance(teacherSchedule);
            totalScore += 1.0 / (1.0 + variance);
        }
        
        return totalScore / teacherSchedules.size();
    }
    
    /**
     * 计算教室利用率分数
     */
    private double calculateClassroomUtilizationScore(List<Schedule> schedules) {
        Map<Long, Long> classroomUsage = schedules.stream()
                .collect(Collectors.groupingBy(Schedule::getClassroomId, Collectors.counting()));
        
        // 计算教室使用率的方差，方差越小说明利用率越均匀
        double mean = classroomUsage.values().stream().mapToLong(Long::longValue).average().orElse(0.0);
        double variance = classroomUsage.values().stream()
                .mapToDouble(count -> Math.pow(count - mean, 2))
                .average().orElse(0.0);
        
        return 1.0 / (1.0 + variance);
    }
    
    /**
     * 计算学生冲突分数
     */
    private double calculateStudentConflictScore(List<Schedule> schedules) {
        // 计算学生课程冲突数量，冲突越少分数越高
        int conflicts = 0;
        for (int i = 0; i < schedules.size(); i++) {
            for (int j = i + 1; j < schedules.size(); j++) {
                if (hasStudentConflict(schedules.get(i), schedules.get(j))) {
                    conflicts++;
                }
            }
        }
        
        return 1.0 / (1.0 + conflicts);
    }
    
    /**
     * 计算教师偏好分数
     */
    private double calculateTeacherPreferenceScore(List<Schedule> schedules) {
        // 根据教师偏好计算分数
        // 这里需要根据实际业务逻辑实现
        return 0.8; // 简化实现
    }
    
    /**
     * 计算时间分布方差
     */
    private double calculateTimeDistributionVariance(List<Schedule> schedules) {
        if (schedules.size() <= 1) return 0.0;
        
        List<Integer> timeSlots = schedules.stream()
                .map(Schedule::getTimeSlotId)
                .map(Long::intValue)
                .sorted()
                .collect(Collectors.toList());
        
        double mean = timeSlots.stream().mapToInt(Integer::intValue).average().orElse(0.0);
        return timeSlots.stream()
                .mapToDouble(slot -> Math.pow(slot - mean, 2))
                .average().orElse(0.0);
    }
    
    /**
     * 检查学生冲突
     */
    private boolean hasStudentConflict(Schedule schedule1, Schedule schedule2) {
        // 如果两个排课是同一个班级，且时间冲突，则存在学生冲突
        return schedule1.getClazzId().equals(schedule2.getClazzId()) &&
               schedule1.getTimeSlotId().equals(schedule2.getTimeSlotId());
    }
}


